/*  This file is part of o.O.

    o.O is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    o.O is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with o.O.  If not, see <http://www.gnu.org/licenses/>.

    Copyright 2013 Oliver Katz */

#include "tokenizer.h"

using namespace std;

namespace oO
{
	void Tokenizer::sortSymbols()
	{
		vector<string> tmp;

		int n = 0;
		for (vector<string>::iterator i = symbols.begin(); i != symbols.end(); i++)
		{
			if (i->size() > n)
				n = i->size();
		}

		for (int i = n; i > 0; i++)
		{
			for (vector<string>::iterator j = symbols.begin(); j != symbols.end(); j++)
			{
				if (j->size() == i)
					tmp.push_back(*j);
			}
		}

		symbols = tmp;
	}

	Tokenizer::Tokenizer(string w, string q, string s)
	{
		debug = false;
		whitespace = w;
		quotes = q;

		vector<Token> tmp = Tokenizer(w).tokenize(s);
		for(vector<Token>::iterator i = tmp.begin(); i != tmp.end(); i++)
			symbols.push_back(i->get());
	}

	void Tokenizer::enableDebugging()
	{
		debug = true;
	}

	vector<Token> Tokenizer::tokenize(string s)
	{
		vector<Token> rtn;
		string buf;

		int l = 0;
		int c = 0;
		bool q = false;

		if (debug)
		{
			cout << "debug: tokenizing '" << s << "'\n";
		}

		for (string::iterator i = s.begin(); i != s.end(); i++)
		{
			if (debug)
			{
				if (*i == '\n')
					cout << "'\\n'\n";
				else
					cout << "'" << *i << "'\n";
			}
			if (quotes.find(*i) != string::npos)
			{
				if (q == true)
				{
					if (debug)
						cout << "  begin quotation...\n";
					q = false;
					buf += *i;
					rtn.push_back(Token(buf, l, c));
					if (debug)
						cout << "  appending '" << buf << "'...\n";
					buf = "";
					continue;
				}
				else
				{
					if (debug)
						cout << " end quotation...\n";
					q = true;
					buf += *i;
					continue;
				}
			}

			if (q)
			{
				if (debug)
					cout << "  within quotation...\n";
				buf += *i;
				continue;
			}

			if (whitespace.find(*i) != string::npos)
			{
				if (debug)
					cout << "  whitespace deliminator...\n";
				if (!buf.empty())
				{
					if (debug)
						cout << "  appending '" << buf << "'...\n";
					rtn.push_back(Token(buf, l, c));
					buf = "";
				}
			}
			else
			{
				bool issym = false;
				for (vector<string>::iterator j = symbols.begin(); j != symbols.end(); j++)
				{
					string cmp(i, i+j->size());
					if (j->compare(cmp) == 0)
					{
						issym = true;

						if (debug)
							cout << "  is symbol...\n";

						if (!buf.empty())
						{
							if (debug)
								cout << "  appending '" << buf << "'...\n";
							rtn.push_back(Token(buf, l, c));
							buf = "";
						}

						if (debug)
							cout << "  appending '" << *j << "'...\n";
						rtn.push_back(Token(*j, l, c));
						i += j->size()-1;

						break;
					}
				}

				if (!issym)
				{
					buf += *i;
				}
			}

			if (*i == '\n')
			{
				l++;
				c = 0;
			}
			else
			{
				c++;
			}
		}

		if (!buf.empty())
		{
			if (debug)
				cout << "  leftover characters in buffer, appending '" << buf << "'...\n";
			rtn.push_back(Token(buf, l, c));
		}

		return rtn;
	}
}
